package cn.edu.sdju.fengguoyu.ahoedgemonitor;

import cn.edu.sdju.fengguoyu.logger.Logger;
import cn.edu.sdju.fengguoyu.po.ServiceInfoTableRow;
import cn.edu.sdju.fengguoyu.proto.*;
import io.grpc.stub.StreamObserver;
import javafx.application.Platform;
import javafx.util.Pair;

import java.util.function.Predicate;

public class AhoEdgeMessageService extends ObserverMessageBroadcastGrpc.ObserverMessageBroadcastImplBase {
    Logger logger = new Logger(AhoEdgeMessageService.class);
    @Override
    public void sendNewServiceMessage(NewServiceMessage request, StreamObserver<AckMessage> responseObserver) {
        ServiceInfoTableRow row = new ServiceInfoTableRow(request.getId(), request.getServerNamed(),String.format("%s:%d", request.getIpAddress(), request.getPort()),"OK");
        row.setType(request.getType());
        App.getApp().serviceInfoTableRowObservableList.add(
                row
        );
        responseObserver.onNext(AckMessage.newBuilder().build());
        responseObserver.onCompleted();
    }

    @Override
    public void sendServiceTimeout(ServiceTimeoutMessage request, StreamObserver<AckMessage> responseObserver) {
        logger.log(String.format("%d Timeout!", request.getId()));
        for (ServiceInfoTableRow row:
             App.getApp().serviceInfoTableRowObservableList) {
            if (row.getId() == request.getId()) {
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        row.setServiceStatus("Timeout");
                    }
                });
                Sprite sprite =  row.getSprite();
                sprite.setStatus(1);
                App.getApp().connections.removeIf(new Predicate<Pair<Sprite, Sprite>>() {
                    @Override
                    public boolean test(Pair<Sprite, Sprite> spriteSpritePair) {
                        return spriteSpritePair.getKey() == sprite || spriteSpritePair.getValue() == sprite;
                    }
                });
            }
        }
        responseObserver.onNext(AckMessage.newBuilder().build());
        responseObserver.onCompleted();
    }

    @Override
    public void sendNewUserMessage(NewUserMessage request, StreamObserver<AckMessage> responseObserver) {
        UserInfoTableRow row = new UserInfoTableRow();
        row.setUserId(request.getId());
        row.want = request.getWant();
        row.setUserAddress(request.getIpAddress());
        App.getApp().userInfoTableRowsObservableList.add(row);
        responseObserver.onNext(AckMessage.newBuilder().build());
        responseObserver.onCompleted();
    }

    @Override
    public void sendUserLeaveMessage(UserLeaveMessage request, StreamObserver<AckMessage> responseObserver) {
        logger.log(String.format("user[%d] quited", request.getId()));
        responseObserver.onNext(AckMessage.newBuilder().build());
        responseObserver.onCompleted();
        for (int i = 0; i < App.getApp().userInfoTableRowsObservableList.size(); i++) {
            if (request.getId() == App.getApp().userInfoTableRowsObservableList.get(i).getUserId()) {
                Sprite user = App.getApp().userInfoTableRowsObservableList.get(i).userSprite;
                App.getApp().connections.removeIf(new Predicate<Pair<Sprite, Sprite>>() {
                    @Override
                    public boolean test(Pair<Sprite, Sprite> spriteSpritePair) {
                        return spriteSpritePair.getKey() == user || spriteSpritePair.getValue() == user;
                    }
                });
                App.getApp().sprites.remove(user);
                App.getApp().userInfoTableRowsObservableList.remove(i);
                return;
            }
        }

    }

    @Override
    public void sendNewConnectionMessage(NewConnectionMessage request, StreamObserver<AckMessage> responseObserver) {
        UserSprite user = null;
        Sprite service = null;
        for (UserInfoTableRow row:
             App.getApp().userInfoTableRowsObservableList) {
            if (row.getUserId() == request.getUserId()) {
                user = row.userSprite;
            }
        }
        for (ServiceInfoTableRow row:
                App.getApp().serviceInfoTableRowObservableList) {
            if (row.getId() == request.getServiceId()) {
                service = row.getSprite();
            }
        }
        if (user != null && service != null) {
            user.startAnimate = false;

            App.getApp().connections.add(new Pair<>(user, service));
        }
        responseObserver.onNext(AckMessage.newBuilder().build());
        responseObserver.onCompleted();
    }

    @Override
    public void sendServiceError(ServiceErrorMessage request, StreamObserver<AckMessage> responseObserver) {
        responseObserver.onNext(AckMessage.newBuilder().build());
        responseObserver.onCompleted();
        System.out.println("Service Error report!");
        for (ServiceInfoTableRow row:
                App.getApp().serviceInfoTableRowObservableList) {
            if (row.getId() == request.getId()) {
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        row.setServiceStatus("DOWN");
                    }
                });
                Sprite sprite =  row.getSprite();
                sprite.setStatus(2);
                App.getApp().connections.removeIf(new Predicate<Pair<Sprite, Sprite>>() {
                    @Override
                    public boolean test(Pair<Sprite, Sprite> spriteSpritePair) {
                        return spriteSpritePair.getKey() == sprite || spriteSpritePair.getValue() == sprite;
                    }
                });
            }
        }

    }

    @Override
    public void sendServiceRank(ServiceRankMessage request, StreamObserver<AckMessage> responseObserver) {
        responseObserver.onNext(AckMessage.newBuilder().build());
        responseObserver.onCompleted();
        for (ServiceInfoTableRow row:
                App.getApp().serviceInfoTableRowObservableList) {
            if (row.getId() == request.getServiceId()) {
                row.setRank(request.getRank());
                logger.log(String.format("service %d Update Rank to %d",request.getServiceId(), request.getRank()));
            }
        }
    }
}
